use std::collections::HashMap;

use model_graph_types::{
    database::{DataSource, DatabaseType},
    datasource::{
        AttributeCondition, DataSourceConnector, QueryCondition, QueryConditionBuilder,
        QueryConditionExpressionBuilder, RelationCondition, RelationConditionBuilder,
    },
    modeling::{
        meta::{
            get_meta_class, get_meta_class_persistence, get_meta_class_relations, get_meta_classes,
            SYSTEM_DOMAIN_IDENTIFIER,
        },
        system_meta_database, Class, ClassAttribute, ClassAttributePersistence, ClassGetter,
        ClassMappingType, ClassPersistence, ClassPersistenceGetter, ClassRelation,
        ComparsionOperator, DataSourceClassAttributeMapping, DataSourceClassMapping,
        DataSourceClassRelationMapping, DataSourceClassRelationMappingBuilder, DataSourceEntity,
        Domain, LogicalOperator, MetaConnector, QueryConditionByClassOptions, Relation,
        RelationDirection, RelationMappingType, RelationRelatedType, Traits, Value, ValueOperator,
    },
};

use crate::connector::SimpleDataSourceConnector;

#[derive(Debug)]
pub struct SimpleMetaConnector {
    pub meta_datasource: DataSource,
}

impl Default for SimpleMetaConnector {
    fn default() -> Self {
        Self {
            meta_datasource: system_meta_database().expect("没有初始化元数据库!"),
        }
    }
}

impl SimpleMetaConnector {
    pub fn new_with_meta_datasource(meta_datasource: &Option<DataSource>) -> anyhow::Result<Self> {
        if let Some(meta_datasource) = meta_datasource {
            Ok(Self {
                meta_datasource: meta_datasource.clone(),
            })
        } else {
            Ok(Self {
                meta_datasource: system_meta_database()?,
            })
        }
    }
}

#[async_trait::async_trait]
impl MetaConnector for SimpleMetaConnector {
    //
    async fn get_class(&self, class_identifier: &String) -> anyhow::Result<Class> {
        if class_identifier.starts_with("g01_") {
            return get_meta_class(class_identifier);
        }
        tracing::debug!("{}", class_identifier,);

        let ds_connector = SimpleDataSourceConnector::default();
        let mut clazz: Class = ds_connector
            .instance_query_one_by_keys(
                &Some(self.meta_datasource.clone()),
                &self.meta_datasource,
                &Class::get_identifier()?,
                vec![class_identifier.clone()],
            )
            .await?
            .try_into()?;
        //查询所有的属性
        let mut attributes = vec![];

        let vs = ds_connector
            .instance_query(
                &Some(self.meta_datasource.clone()),
                &self.meta_datasource,
                &ClassAttribute::get_identifier()?,
                QueryCondition::with_attribute(
                    String::from("class_identifier"),
                    class_identifier.clone(),
                )?,
                None,
                None,
            )
            .await?
            .data;
        let mut keys: Vec<String> = vec![];
        for v in vs {
            let attr: ClassAttribute = v.try_into()?;
            if attr.is_key {
                keys.push(attr.name.clone());
            }
            attributes.push(attr);
        }
        tracing::debug!("keys:{:#?}", keys);
        clazz.attributes = Some(attributes);
        if clazz.primary_key == "" && keys.len() > 0 {
            clazz.primary_key = keys.join(",");
        }
        Ok(clazz)
    }

    async fn get_relation(&self, relation_identifier: &String) -> anyhow::Result<Relation> {
        Err(anyhow::anyhow!(""))
    }

    /// 通过领域获取，所有的类
    async fn domain_classes(&self, domain_identifier: &String) -> anyhow::Result<Vec<Class>> {
        if domain_identifier == SYSTEM_DOMAIN_IDENTIFIER {
            return get_meta_classes();
        }
        let ds_connector = SimpleDataSourceConnector::default();

        let meta_datasource = system_meta_database()?;

        let values = ds_connector
            .instance_query(
                &Some(meta_datasource.clone()),
                &meta_datasource,
                &Class::get_identifier()?,
                QueryCondition::with_attribute(
                    String::from("domain_identifier"),
                    domain_identifier.clone(),
                )?,
                None,
                None,
            )
            .await?
            .data;
        let mut res = vec![];
        for value in values {
            res.push(value.try_into()?);
        }
        Ok(res)
    }

    async fn get_class_persistence(
        &self,
        class_identifier: &String,
    ) -> anyhow::Result<ClassPersistence> {
        //
        if class_identifier.starts_with("g01_") {
            return Ok(get_meta_class_persistence(class_identifier)?
                .map_or(Err(anyhow::anyhow!("{}", class_identifier)), |v| Ok(v))?);
        }
        let class = self.get_class(class_identifier).await?;
        let ds_connector = SimpleDataSourceConnector::default();

        if class_identifier == &DataSourceClassMapping::get_identifier()? {
            return DataSourceClassMapping::class_persistence()?.map_or(
                Err(anyhow::anyhow!(
                    "DataSourceClassMapping::class_persistence异常"
                )),
                |v| Ok(v),
            );
        }
        let mut persistence = ClassPersistence::default();

        //如果是系统表
        if let Ok(Some(persistence)) = get_meta_class_persistence(class_identifier) {
            return Ok(persistence);
        }

        //获取是否有存储的映射
        let mut conditions = QueryCondition::with_attribute(
            String::from("domain_identifier"),
            class.domain_identifier.clone(),
        )?;

        conditions.set_attribute(String::from("class_identifier"), class_identifier.clone())?;
        if let Ok(item) = ds_connector
            .instance_query_one(
                &Some(self.meta_datasource.clone()),
                &self.meta_datasource,
                &DataSourceClassMapping::get_identifier()?,
                conditions,
                None,
                None,
            )
            .await
        {
            //
            let class_mapping: DataSourceClassMapping = item.try_into()?;
            match &class_mapping.mapping_type {
                ClassMappingType::Table => {
                    //表名
                    persistence.table_name = class_mapping
                        .table_name
                        .as_ref()
                        .map_or(class.name.clone(), |v| v.clone());
                    //继续查询是否存在属性映射
                    let mut attr_conditions: QueryCondition = QueryCondition::with_attribute(
                        String::from("class_identifier"),
                        class_identifier.clone(),
                    )?;

                    if let Ok(v) = ds_connector
                        .instance_query(
                            &Some(self.meta_datasource.clone()),
                            &self.meta_datasource,
                            &DataSourceClassAttributeMapping::get_identifier()?,
                            attr_conditions,
                            None,
                            None,
                        )
                        .await
                    {
                        //
                        let attr_mappings = v
                            .data
                            .iter()
                            .map(|item| {
                                item.clone()
                                    .try_into()
                                    .map_or(DataSourceClassAttributeMapping::default(), |r| r)
                            })
                            .fold(
                                HashMap::<String, DataSourceClassAttributeMapping>::new(),
                                |mut map, item| {
                                    map.insert(item.class_attribute_identifier.clone(), item);
                                    map
                                },
                            );
                        //
                        let mut attr_persistences: Vec<ClassAttributePersistence> = vec![];
                        if let Some(attributes) = &class.attributes {
                            for attribute in attributes {
                                //
                                if let Some(attr_mapping) = attr_mappings.get(&attribute.identifier)
                                {
                                    //
                                    attr_persistences
                                        .push(ClassAttributePersistence::try_from(attr_mapping)?);
                                } else {
                                    attr_persistences
                                        .push(ClassAttributePersistence::try_from(attribute)?);
                                }
                            }
                        } else {
                        }
                        persistence.columns = attr_persistences;
                    }
                }
                ClassMappingType::SQL => {}
                _ => {}
            }

            Ok(persistence)
        } else {
            //没有配置映射，直接返回identifier
            //获取表名
            persistence.table_name = class.name.clone();

            let mut attr_persistences: Vec<ClassAttributePersistence> = vec![];
            if let Some(attributes) = &class.attributes {
                for attribute in attributes {
                    //
                    attr_persistences.push(ClassAttributePersistence::try_from(attribute)?);
                }
            } else {
            }
            persistence.columns = attr_persistences;
            Ok(persistence)
        }
    }

    async fn query_condition_by_class_object(
        &self,
        value_class_identifier: &String,
        other_class_identifier: &String,
        object: &Value,
        relation_conditions: &Option<RelationCondition>,
        options: QueryConditionByClassOptions,
    ) -> anyhow::Result<QueryCondition> {
        //暂时
        let depth = if let Some(depth) = &options.depth {
            *depth
        } else {
            1_i32
        };
        //
        let value_class = self.get_class(value_class_identifier).await?;
        let other_class = self.get_class(other_class_identifier).await?;

        let mut condition = QueryConditionBuilder::default();

        let class_condition = RelationConditionBuilder::default()
            .class_identifier(value_class_identifier)
            .build()?;

        let rc = if let Some(rc) = relation_conditions {
            let mut rc = rc.clone();
            rc.combine(&class_condition)?;
            rc
        } else {
            class_condition
        };
        let mut relation_mappings = self.class_relations(other_class_identifier, &rc).await?;
        relation_mappings.append(&mut self.class_relations(value_class_identifier, &rc).await?);

        if let Some(relation_mapping) = relation_mappings.get(0) {
            match &relation_mapping.related_type {
                RelationRelatedType::Keys => {
                    //关系属性
                    if value_class_identifier == &relation_mapping.src_identifier {
                        //正向关系
                        condition.attributes(vec![AttributeCondition::new_with_equal(
                            relation_mapping.related_at.clone(),
                            object
                                .clone()
                                .value_from_key(&value_class.primary_key)
                                .map_or(
                                    Err(anyhow::anyhow!(
                                        "没有值:{:?} [{}]",
                                        object,
                                        value_class.primary_key
                                    )),
                                    |v| Ok(v),
                                )?
                                .try_into()?,
                        )]);
                    } else {
                        //反向关系
                        condition.attributes(vec![AttributeCondition::new_with_equal(
                            other_class.primary_key.clone(),
                            object
                                .clone()
                                .value_from_key(&relation_mapping.related_at)
                                .map_or(
                                    Err(anyhow::anyhow!(
                                        "没有值:{:?} [{}]",
                                        object,
                                        relation_mapping.related_at
                                    )),
                                    |v| Ok(v),
                                )?
                                .try_into()?,
                        )]);
                    }
                }
                RelationRelatedType::Class => {
                    let table_name = relation_mapping.related_at.clone();
                    tracing::debug!("======={}", table_name);
                    //关系属性
                    if value_class_identifier == &relation_mapping.src_identifier {
                        //正向关系
                    } else {
                        //反向关系
                    }
                }
                _ => {}
            }
        }

        Ok(condition.build()?)
    }

    async fn class_relations(
        &self,
        class_identifier: &String,
        condition: &RelationCondition,
    ) -> anyhow::Result<Vec<ClassRelation>> {
        tracing::debug!("class_relations:[{}]{:?}", class_identifier, condition);
        //是否是系统关系
        if let Ok(v) = get_meta_class_relations(class_identifier, &Some(condition.clone())) {
            return Ok(v);
        }

        let ds_connector = SimpleDataSourceConnector::default();
        //查询关系
        let mut conditions = QueryCondition::default();

        // 本类条件
        if let Some(direction) = &condition.direction {
            match direction {
                RelationDirection::Obverse => {
                    conditions
                        .set_attribute(String::from("src_identifier"), class_identifier.clone())?;
                }
                RelationDirection::Reverse => {
                    conditions.set_attribute(
                        String::from("target_identifier"),
                        class_identifier.clone(),
                    )?;
                }
            }
        } else {
            conditions.set_expression(
                QueryConditionExpressionBuilder::default()
                    .operator(LogicalOperator::Or)
                    .left_expression(
                        QueryConditionExpressionBuilder::default()
                            .operator(LogicalOperator::Comparsion(ComparsionOperator::Equal))
                            .left("target_identifier")
                            .value(class_identifier.clone())
                            .build()?,
                    )
                    .right_expression(
                        QueryConditionExpressionBuilder::default()
                            .operator(LogicalOperator::Comparsion(ComparsionOperator::Equal))
                            .left("src_identifier")
                            .value(class_identifier.clone())
                            .build()?,
                    )
                    .build()?,
                LogicalOperator::And,
            )?;
        }

        //关系类条件
        if let Some(identifier) = &condition.class_identifier {
            //针对与被查询的类的方向
            if let Some(direction) = &condition.direction {
                match direction {
                    RelationDirection::Obverse => {
                        conditions
                            .set_attribute(String::from("target_identifier"), identifier.clone())?;
                    }
                    RelationDirection::Reverse => {
                        conditions
                            .set_attribute(String::from("src_identifier"), identifier.clone())?;
                    }
                }
            } else {
                // or 条件
                conditions.set_expression(
                    QueryConditionExpressionBuilder::default()
                        .operator(LogicalOperator::Or)
                        .left_expression(
                            QueryConditionExpressionBuilder::default()
                                .operator(LogicalOperator::Comparsion(ComparsionOperator::Equal))
                                .left("target_identifier")
                                .value(identifier.clone())
                                .build()?,
                        )
                        .right_expression(
                            QueryConditionExpressionBuilder::default()
                                .operator(LogicalOperator::Comparsion(ComparsionOperator::Equal))
                                .left("src_identifier")
                                .value(identifier.clone())
                                .build()?,
                        )
                        .build()?,
                    LogicalOperator::And,
                )?;
            }
        }
        //类型
        if let Some(relation_identifier) = &condition.relation_identifier {
            conditions.set_attribute(
                String::from("relation_identifier"),
                relation_identifier.clone(),
            )?;
        }
        //
        if let Some(related_type) = &condition.related_type {
            conditions
                .set_attribute(String::from("related_type"), format!("{:?}", related_type))?;
        }
        //
        if let Some(related_at) = &condition.related_at {
            conditions.set_attribute(String::from("related_at"), related_at.clone())?;
        }
        tracing::debug!("查询:{:?}", conditions);
        let rows = ds_connector
            .instance_query(
                &Some(self.meta_datasource.clone()),
                &self.meta_datasource,
                &ClassRelation::get_identifier()?,
                conditions.clone(),
                None,
                None,
            )
            .await?
            .data;
        tracing::debug!("关系:{:?}", rows);

        let mut res = vec![];
        for row in rows {
            res.push(ClassRelation::try_from(row)?);
        }

        Ok(res)
    }

    async fn relation_mapping(
        &self,
        class_identifier: &String,
        condition: &RelationCondition,
    ) -> anyhow::Result<Vec<DataSourceClassRelationMapping>> {
        let ds_connector = SimpleDataSourceConnector::default();

        let relations = self.class_relations(class_identifier, condition).await?;

        tracing::debug!("=======");
        let mut res = vec![];

        for relation in relations {
            //
            match &relation.related_type {
                RelationRelatedType::Keys => {
                    //
                    let src_class = self.get_class(&relation.src_identifier).await?;
                    res.push(
                        DataSourceClassRelationMappingBuilder::default()
                            .relation_identifier(relation.relation_identifier.clone())
                            .src_identifier(relation.src_identifier.clone())
                            .target_identifier(relation.target_identifier.clone())
                            .src_keys(src_class.primary_key.clone())
                            .target_keys(&relation.related_at)
                            .build()?,
                    );
                    continue;
                }
                RelationRelatedType::Class => {
                    // TODO
                    // let src_class = self.get_class(&relation.src_identifier).await?;
                    // res.push(
                    //     DataSourceClassRelationMappingBuilder::default()
                    //         .relation_identifier(relation.relation_identifier.clone())
                    //         .src_identifier(relation.src_identifier.clone())
                    //         .target_identifier(relation.target_identifier.clone())
                    //         .src_keys(src_class.primary_key.clone())
                    //         .target_keys(&relation.related_at)
                    //         .build()?,
                    // );
                    continue;
                }
                _ => {
                    //查询关系
                    let mut conditions = QueryCondition::default();
                    conditions.set_attribute(
                        String::from("relation_identifier"),
                        relation.relation_identifier.clone(),
                    )?;
                    //根据关系，继续查询映射表
                    if let Ok(v) = ds_connector
                        .instance_query_one(
                            &Some(self.meta_datasource.clone()),
                            &self.meta_datasource,
                            &DataSourceClassRelationMapping::get_identifier()?,
                            conditions,
                            None,
                            None,
                        )
                        .await
                    {
                        let relation_mapping: DataSourceClassRelationMapping = v.try_into()?;
                        tracing::debug!("relation_mapping:{:?}", relation_mapping);

                        res.push(relation_mapping);
                    } else {
                        //获取class name
                        let src_class = self.get_class(&relation.src_identifier).await?;
                        // let target_class = self.get_class(&relation.target_identifier).await?;
                        // TODO 根据关系的类型进行默认的处理
                        res.push(
                            DataSourceClassRelationMappingBuilder::default()
                                .relation_identifier(relation.relation_identifier.clone())
                                .src_identifier(relation.src_identifier.clone())
                                .target_identifier(relation.target_identifier.clone())
                                .src_keys(src_class.primary_key.clone())
                                .target_keys(&relation.related_at)
                                .build()?,
                        );
                    }
                }
            }
        }

        Ok(res)
    }

    async fn generate_sql(
        &self,
        domain_identifier: &String,
        database_type: DatabaseType,
    ) -> anyhow::Result<Vec<String>> {
        crate::modeling::generate_sql(domain_identifier, database_type).await
    }
}
